home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2009 February / PCWFEB09.iso / Software / Freeware / Griffith 0.9.8 / griffith-0.9.8-win32.exe / {app} / lib / gutils.py < prev    next >
Text File  |  2008-11-17  |  15KB  |  581 lines

  1. # -*- coding: UTF-8 -*-
  2.  
  3. __revision__ = '$Id: gutils.py 1040 2008-11-15 21:13:49Z mikej06 $'
  4.  
  5. # Copyright (c) 2005-2008 Vasco Nunes, Piotr O┼╝arowski
  6. #
  7. # This program is free software; you can redistribute it and/or modify
  8. # it under the terms of the GNU General Public License as published by
  9. # the Free Software Foundation; either version 2 of the License, or
  10. # (at your option) any later version.
  11. #
  12. # This program is distributed in the hope that it will be useful,
  13. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15. # GNU Library General Public License for more details.
  16. #
  17. # You should have received a copy of the GNU General Public License
  18. # along with this program; if not, write to the Free Software
  19. # 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
  20.  
  21. # You may use and distribute this software under the terms of the
  22. # GNU General Public License, version 2 or later
  23.  
  24. import string
  25. import os
  26. try:
  27.     import gtk
  28.     import gobject
  29. except:
  30.     pass
  31. import htmlentitydefs
  32. import re
  33. import webbrowser
  34.  
  35. url_re = re.compile('^\w+://')
  36. entity = re.compile(r'\&.\w*?\;')
  37. html_tags = re.compile(r'\<.*?\>')
  38.  
  39. def remove_accents(txt, encoding='iso-8859-1'):
  40.     d = {192: u'A', 193: u'A', 194: u'A', 195: u'A', 196: u'A', 197: u'A',
  41.             199: u'C', 200: u'E', 201: u'E', 202: u'E', 203: u'E', 204: u'I',
  42.             205: u'I', 206: u'I', 207: u'I', 209: u'N', 210: u'O', 211: u'O',
  43.             212: u'O', 213: u'O', 214: u'O', 216: u'O', 217: u'U', 218: u'U',
  44.             219: u'U', 220: u'U', 221: u'Y', 224: u'a', 225: u'a', 226: u'a',
  45.             227: u'a', 228: u'a', 229: u'a', 231: u'c', 232: u'e', 233: u'e',
  46.             234: u'e', 235: u'e', 236: u'i', 237: u'i', 238: u'i', 239: u'i',
  47.             241: u'n', 242: u'o', 243: u'o', 244: u'o', 245: u'o', 246: u'o',
  48.             248: u'o', 249: u'u', 250: u'u', 251: u'u', 252: u'u', 253: u'y',
  49.             255: u'y'}
  50.     return unicode(txt, encoding).translate(d)
  51.  
  52. def is_number(x):
  53.     return isinstance(x, int)
  54.  
  55. def find_next_available(db):
  56.     """
  57.     finds next available movie number.
  58.     This is the first empty position.
  59.     If none is empty then increments the last position.
  60.     """
  61.     first = 0
  62.  
  63.     movies = db.Movie.select(order_by="number ASC")
  64.     for movie in movies:
  65.         second = int(movie.number)
  66.         if second is None:
  67.             second = 0
  68.         if (second>first+1):
  69.             break
  70.         first = second
  71.  
  72.     if first is None:
  73.         return 1
  74.     else:
  75.         number = first+1
  76.         return number
  77.  
  78. def trim(text,key1,key2):
  79.     p1 = string.find(text,key1)
  80.     if p1 == -1:
  81.         return ""
  82.     else:
  83.         p1 = p1+len(key1)
  84.     p2 = string.find(text[p1:],key2)
  85.     if p2 == -1:
  86.         return ""
  87.     else:
  88.         p2 = p1+p2
  89.     return text[p1:p2]
  90.  
  91. def after(text,key):
  92.     p1 = string.find(text,key)
  93.     return text[p1+len(key):]
  94.  
  95. def before(text,key):
  96.     p1 = string.find(text,key)
  97.     return text[:p1]
  98.  
  99. def gescape(text):
  100.     text=string.replace(text,"'", "''")
  101.     text=string.replace(text,"--", "-")
  102.     return text
  103.  
  104. def progress(blocks,size_block,size):
  105.     transfered = blocks * size_block
  106.     if size > 0 and transfered > size:
  107.         transfered = size
  108.     elif size < 0:
  109.         size = "?"
  110.     print transfered, '/', size, 'bytes'
  111.  
  112. # functions to handle comboboxentry stuff
  113.  
  114. def set_model_from_list (cb, items):
  115.     """Setup a ComboBox or ComboBoxEntry based on a list of strings."""
  116.     model = gtk.ListStore(str)
  117.     for i in items:
  118.         model.append([i])
  119.     cb.set_model(model)
  120.     if type(cb) == gtk.ComboBoxEntry:
  121.         cb.set_text_column(0)
  122.     elif type(cb) == gtk.ComboBox:
  123.         cell = gtk.CellRendererText()
  124.         cb.pack_start(cell, True)
  125.         cb.add_attribute(cell, 'text', 0)
  126.  
  127. def on_combo_box_entry_changed(widget):
  128.     model = widget.get_model()
  129.     m_iter = widget.get_active_iter()
  130.     if m_iter:
  131.         return model.get_value(m_iter, 0)
  132.     else:
  133.         return 0
  134.  
  135. def on_combo_box_entry_changed_name(widget):
  136.     return widget.get_active_text().decode('utf-8')
  137.  
  138. def convert_entities(text):
  139.     def conv(ents):
  140.         entities = htmlentitydefs.entitydefs
  141.         ents = ents.group(0)
  142.         ent_code = entities.get(ents[1:-1], None)
  143.         if ent_code:
  144.             try:
  145.                 ents = unicode(ent_code, 'UTF-8')
  146.             except UnicodeDecodeError:
  147.                 ents = unicode(ent_code, 'latin-1')
  148.             except Exception, ex:
  149.                 print("error occurred while converting entity %s: %s" % (ents, ex))
  150.  
  151.             # check if it still needs conversion
  152.             if not entity.search(ents):
  153.                 return ents
  154.  
  155.         if ents[1] == '#':
  156.             code = ents[2:-1]
  157.             base = 10
  158.             if code[0] == 'x':
  159.                 code = code[1:]
  160.                 base = 16
  161.             return unichr(int(code, base))
  162.         else:
  163.             return
  164.  
  165.     in_entity = entity.search(text)
  166.     if not in_entity:
  167.         return text
  168.     else:
  169.         ctext = in_entity.re.sub(conv, text)
  170.         return ctext
  171.  
  172. def strip_tags(text):
  173.     if text is None:
  174.         return ''
  175.     finished = 0
  176.     while not finished:
  177.         finished = 1
  178.         # check if there is an open tag left
  179.         start = text.find("<")
  180.         if start >= 0:
  181.             # if there is, check if the tag gets closed
  182.             stop = text[start:].find(">")
  183.             if stop >= 0:
  184.                 # if it does, strip it, and continue loop
  185.                 text = text[:start] + text[start+stop+1:]
  186.                 finished = 0
  187.     return text
  188.  
  189. def save_pixmap(self, pixmap, filename):
  190.     pixmap.save(filename, "jpeg", {"quality":"70"})
  191.  
  192. def clean(text):
  193.     t = strip_tags(text)
  194.     t = string.replace(t, ' ', ' ')
  195.     t = string.replace(t, '"', '')
  196.     t = string.replace(t, ' ', ' ')
  197.     return string.strip(t)
  198.  
  199. def gdecode(txt, encode):
  200.     try:
  201.         return txt.decode(encode)
  202.     except:
  203.         return txt
  204.  
  205. # Messages
  206.  
  207. def error(self, msg, parent=None):
  208.     dialog = gtk.MessageDialog(parent,
  209.             gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
  210.             gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, msg)
  211.     dialog.set_skip_taskbar_hint(False)
  212.     dialog.run()
  213.     dialog.destroy()
  214.  
  215. def urllib_error(msg, parent=None):
  216.     dialog = gtk.MessageDialog(parent,
  217.             gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
  218.             gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, msg)
  219.     dialog.set_skip_taskbar_hint(False)
  220.     dialog.run()
  221.     dialog.destroy()
  222.  
  223. def warning(self, msg, parent=None):
  224.     dialog = gtk.MessageDialog(parent,
  225.             gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
  226.             gtk.MESSAGE_WARNING, gtk.BUTTONS_OK, msg)
  227.     dialog.set_skip_taskbar_hint(False)
  228.     dialog.run()
  229.     dialog.destroy()
  230.  
  231. def info(self, msg, parent=None):
  232.     dialog = gtk.MessageDialog(parent,
  233.             gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
  234.             gtk.MESSAGE_INFO, gtk.BUTTONS_OK, msg)
  235.     dialog.set_skip_taskbar_hint(False)
  236.     dialog.run()
  237.     dialog.destroy()
  238.  
  239. def question(self, msg, cancel=1, parent=None):
  240.     if not parent: parent = self
  241.     dialog = gtk.MessageDialog(parent,
  242.             gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
  243.             gtk.MESSAGE_QUESTION, gtk.BUTTONS_NONE, msg)
  244.     dialog.add_buttons(gtk.STOCK_YES, gtk.RESPONSE_YES,
  245.             gtk.STOCK_NO, gtk.RESPONSE_NO)
  246.     dialog.set_default_response(gtk.RESPONSE_NO)
  247.     dialog.set_skip_taskbar_hint(False)
  248.     response = dialog.run()
  249.     dialog.destroy()
  250.     return response
  251.  
  252. def file_chooser(title, action=None, buttons=None, name="", folder=os.path.expanduser("~"), picture = False):
  253.     dialog = gtk.FileChooserDialog(title=title, action=action, buttons=buttons)
  254.     dialog.set_default_response(gtk.RESPONSE_OK)
  255.     if name:
  256.         dialog.set_current_name(name)
  257.     if folder:
  258.         dialog.set_current_folder(folder)
  259.     mfilter = gtk.FileFilter()
  260.     if picture==True:
  261.         preview = gtk.Image()
  262.         dialog.set_preview_widget(preview)
  263.         dialog.connect("update-preview", update_preview_cb, preview)
  264.         mfilter.set_name(_("Images"))
  265.         mfilter.add_mime_type("image/png")
  266.         mfilter.add_mime_type("image/jpeg")
  267.         mfilter.add_mime_type("image/gif")
  268.         mfilter.add_pattern("*.[pP][nN][gG]")
  269.         mfilter.add_pattern("*.[jJ][pP][eE][gG]")
  270.         mfilter.add_pattern("*.[gG][iI][fF]")
  271.         mfilter.add_pattern("*.[tT][iI][fF]{1,2}")
  272.         mfilter.add_pattern("*.[xX][pP][mM]")
  273.         dialog.add_filter(mfilter)
  274.     mfilter = gtk.FileFilter()
  275.     mfilter.set_name(_("All files"))
  276.     mfilter.add_pattern("*")
  277.     dialog.add_filter(mfilter)
  278.  
  279.  
  280.     response = dialog.run()
  281.     if response == gtk.RESPONSE_OK:
  282.         filename = dialog.get_filename()
  283.     elif response == gtk.RESPONSE_CANCEL:
  284.         filename = None
  285.     else:
  286.         return False
  287.     path = dialog.get_current_folder()
  288.     dialog.destroy()
  289.     return filename, path
  290.  
  291. def update_preview_cb(file_chooser, preview):
  292.     filename = file_chooser.get_preview_filename()
  293.     try:
  294.         pixbuf = gtk.gdk.pixbuf_new_from_file_at_size(filename, 128, 128)
  295.         preview.set_from_pixbuf(pixbuf)
  296.         have_preview = True
  297.     except:
  298.         have_preview = False
  299.     file_chooser.set_preview_widget_active(have_preview)
  300.     return
  301.  
  302. def run_browser(url):
  303.     webbrowser.register('open', webbrowser.GenericBrowser("open '%s'"))
  304.     webbrowser._tryorder.append('open')
  305.     webbrowser.open(url)
  306.  
  307. def read_plugins(prefix,directory):
  308.     """returns available plugins"""
  309.     import glob
  310.     return glob.glob("%s/%s*.py" % (directory,prefix) )
  311.  
  312. def findKey(val, dict):
  313.     for key, value in dict.items():
  314.         if value == val: return key
  315.     return None
  316.  
  317. def garbage(handler):
  318.     pass
  319.  
  320. def make_thumbnail(self, file_name):
  321.     source = os.path.join(self.locations['posters'], file_name)
  322.     if os.path.isfile(source):
  323.         self.Image.set_from_file(source)
  324.         pixbuf = self.Image.get_pixbuf()
  325.         pixbuf = pixbuf.scale_simple(30, 40, 'bilinear')
  326.         save_pixmap(self, pixbuf, os.path.join(self.locations['posters'], "t_%s"%file_name))
  327.     else:
  328.         return 0
  329.  
  330. def make_medium_image(self, file_name):
  331.     source = os.path.join(self.locations['posters'], file_name)
  332.     if os.path.isfile(source):
  333.         self.Image.set_from_file(source)
  334.         pixbuf = self.Image.get_pixbuf()
  335.         pixbuf = pixbuf.scale_simple(100, 140, 'bilinear')
  336.         save_pixmap(self, pixbuf, os.path.join(self.locations['posters'], "m_%s"%file_name))
  337.     else:
  338.         return 0
  339.  
  340. def clean_posters_dir(self):
  341.     posters_dir = self.locations['posters']
  342.  
  343.     counter = 0
  344.  
  345.     for files in os.walk(posters_dir):
  346.         for names in files:
  347.             for name in names:
  348.                 if name.startswith('poster'):
  349.                     # lets check if this poster is orphan
  350.                     used = self.db.Movie.count_by(image=string.replace(name,".jpg",""))
  351.                     if not used:
  352.                         counter += 1
  353.                         os.unlink(os.path.join(posters_dir, name))
  354.                         m_file = os.path.join(posters_dir, "m_"+name)
  355.                         if os.path.isfile(m_file):
  356.                             os.unlink(m_file)
  357.                         t_file = os.path.join(posters_dir, "t_"+name)
  358.                         if os.path.isfile(t_file):
  359.                             os.unlink(t_file)
  360.  
  361.     if counter:
  362.         print "%d orphan files cleaned."%counter
  363.     else:
  364.         print "No orphan files found."
  365.  
  366. def decompress(data):
  367.     import gzip, StringIO
  368.     try:
  369.         compressedStream = StringIO.StringIO(data)
  370.         gzipper = gzip.GzipFile(fileobj=compressedStream)
  371.         data = gzipper.read()
  372.     except:
  373.         pass
  374.     return data
  375.  
  376. def get_dependencies():
  377.     depend = []
  378.     try:
  379.         import gtk
  380.         version    = '.'.join([str(i) for i in gtk.pygtk_version])
  381.         if gtk.pygtk_version <= (2, 6, 0):
  382.             version = '-%s' % version
  383.     except:
  384.         version = False
  385.     depend.append({'module': 'gtk',
  386.         'version'    : version,
  387.         'module_req'    : '2.6',
  388.         'url'        : 'http://www.pygtk.org/',
  389.         'debian'    : 'python-gtk2',
  390.         'debian_req'    : '2.8.6-1'
  391.         # TODO: 'fedora', 'suse', etc.
  392.     })
  393.     try:
  394.         import gtk.glade
  395.         # (version == gtk.pygtk_version)
  396.     except:
  397.         version = False
  398.     depend.append({'module': 'gtk.glade',
  399.         'version'    : version,
  400.         'module_req'    : '2.6',
  401.         'url'        : 'http://www.pygtk.org/',
  402.         'debian'    : 'python-glade2',
  403.         'debian_req'    : '2.8.6-1'
  404.     })
  405.     try:
  406.         import sqlalchemy
  407.         version = True
  408.     except:
  409.         version = False
  410.     depend.append({'module': 'sqlalchemy',
  411.         'version'    : version,
  412.         'module_req'    : '0.3.10',
  413.         'url'        : 'http://www.sqlalchemy.org/',
  414.         'debian'    : 'python-sqlalchemy',
  415.         'debian_req'    : '0.3.10-1'
  416.     })
  417.     try:
  418.         import sqlite3
  419.         version = sqlite3.version
  420.     except ImportError:
  421.         version = False
  422.     if version is False:
  423.         try:
  424.             import pysqlite2
  425.             version = True
  426.         except:
  427.             version = False
  428.         depend.append({'module': 'pysqlite2',
  429.             'version'    : version,
  430.             'url'        : 'http://initd.org/tracker/pysqlite',
  431.             'debian'    : 'python-pysqlite2',
  432.             'debian_req'    : '2.3.0-1'
  433.         })
  434.     else:
  435.         depend.append({'module': 'sqlite3',
  436.             'version'    : version,
  437.             'url'        : 'http://www.python.org',
  438.             'debian'    : 'python',
  439.             'debian_req'    : '2.5'
  440.         })
  441.     try:
  442.         import reportlab
  443.         version = reportlab.Version
  444.     except:
  445.         version = False
  446.     depend.append({'module': 'reportlab',
  447.         'version'    : version,
  448.         'url'        : 'http://www.reportlab.org/',
  449.         'debian'    : 'python-reportlab',
  450.         'debian_req'    : '1.20debian-6'
  451.     })
  452.     try:
  453.         import PIL
  454.         version = True
  455.     except:
  456.         version = False
  457.     depend.append({'module': 'PIL',
  458.         'version'    : version,
  459.         'url'        : 'http://www.pythonware.com/products/pil/',
  460.         'debian'    : 'python-imaging',
  461.         'debian_req'    : '1.1.5-6'
  462.     })
  463.     try:
  464.         import xml
  465.         version = xml.__version__
  466.     except:
  467.         version = False
  468.     depend.append({'module': 'xml',
  469.         'version'    : version,
  470.         'url'        : 'http://pyxml.sf.net/',
  471.         'debian'    : 'python-xml'
  472.     })
  473.     # extra dependencies:
  474.     optional = []
  475.     try:
  476.         import psycopg2
  477.         version = psycopg2.__version__
  478.     except:
  479.         version = False
  480.     optional.append({'module': 'psycopg2',
  481.         'version'    : version,
  482.         'url'        : 'http://initd.org/tracker/psycopg/wiki/PsycopgTwo',
  483.         'debian'    : 'python-psycopg2',
  484.         'debian_req'    : '1.1.21-6'
  485.     })
  486.     try:
  487.         import MySQLdb
  488.         version    = '.'.join([str(i) for i in MySQLdb.version_info])
  489.     except:
  490.         version = False
  491.     optional.append({'module': 'MySQLdb',
  492.         'version'    : version,
  493.         'url'        : 'http://sourceforge.net/projects/mysql-python',
  494.         'debian'    : 'python-mysqldb',
  495.         'debian_req'    : '1.2.1-p2-2'
  496.     })
  497.     try:
  498.         import chardet
  499.         version    = chardet.__version__
  500.     except:
  501.         version = False
  502.     optional.append({'module': 'chardet',
  503.         'version'    : version,
  504.         'url'        : 'http://chardet.feedparser.org/',
  505.         'debian'    : 'python-chardet'
  506.     })
  507.     try:
  508.         import sqlite
  509.         version    = sqlite.version
  510.     except:
  511.         version = False
  512.     optional.append({'module': 'sqlite',
  513.         'version'    : version,
  514.         'url'        : 'http://initd.org/tracker/pysqlite',
  515.         'debian'    : 'python-sqlite'
  516.     })
  517.     return depend, optional
  518.  
  519.  
  520. def html_encode(s):
  521.     if not isinstance(s, str):
  522.         s = str(s)
  523.     s = s.replace('&', '&')
  524.     s = s.replace('<', '<')
  525.     s = s.replace('>', '>')
  526.     s = s.replace('"', '"')
  527.     return s
  528.  
  529. def digits_only(s, maximum=None):
  530.     if s is None:
  531.         return 0
  532.     import string, re
  533.     match = re.compile(r"\d+")
  534.     a = match.findall(str(s))
  535.     if len(a):
  536.         s = int(a[0])
  537.     else:
  538.         s = 0
  539.     if maximum is None:
  540.         return s
  541.     else:
  542.         if s > maximum:
  543.             return maximum
  544.         else:
  545.             return s
  546.  
  547. def copytree(src, dst, symlinks=False):
  548.     """Recursively copy a directory tree using copy2().
  549.  
  550.     This is shutil's copytree modified version
  551.     """
  552.     from shutil import copy2
  553.     names = os.listdir(src)
  554.     if not os.path.isdir(dst):
  555.         os.mkdir(dst)
  556.     errors = []
  557.     for name in names:
  558.         srcname = os.path.join(src, name)
  559.         dstname = os.path.join(dst, name)
  560.         try:
  561.             if symlinks and os.path.islink(srcname):
  562.                 linkto = os.readlink(srcname)
  563.                 os.symlink(linkto, dstname)
  564.             elif os.path.isdir(srcname):
  565.                 copytree(srcname, dstname, symlinks)
  566.             else:
  567.                 copy2(srcname, dstname)
  568.         except (IOError, os.error), why:
  569.             errors.append((srcname, dstname, why))
  570.         # catch the Error from the recursive copytree so that we can
  571.         # continue with other files
  572.         except EnvironmentError, err:
  573.             errors.extend(err.args[0])
  574.     if errors:
  575.         raise EnvironmentError, errors
  576.  
  577. def is_windows_system():
  578.     if os.name == 'nt' or os.name.startswith('win'): # win32, win64
  579.         return True
  580.     return False
  581.